"""
数据库测试基类
提供数据库集成测试的通用功能和基础设置
"""

import pytest
from typing import Any, Dict, Optional
from unittest.mock import Mock, patch
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.pool import StaticPool

from app.core.database import Base
from app.models.user import User
from app.models.role import Role
from app.models.permission import Permission
from app.models.user_role import UserRole
from app.models.role_permission import RolePermission

from tests.utils import (
    create_mock_user,
    create_mock_role,
    create_mock_permission
)


class BaseDBTest:
    """数据库测试基类"""
    
    # 数据库相关
    engine = None
    TestingSessionLocal = None
    db: Optional[Session] = None
    
    # 测试数据
    test_user: Optional[User] = None
    test_role: Optional[Role] = None
    test_permission: Optional[Permission] = None
    
    @classmethod
    def setup_class(cls):
        """测试类设置 - 创建内存数据库"""
        # 创建内存数据库引擎
        cls.engine = create_engine(
            "sqlite:///:memory:",
            connect_args={"check_same_thread": False},
            poolclass=StaticPool,
        )
        
        # 创建所有表
        Base.metadata.create_all(bind=cls.engine)
        
        # 创建会话工厂
        cls.TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=cls.engine)
    
    @classmethod
    def teardown_class(cls):
        """测试类清理 - 关闭数据库连接"""
        if cls.engine:
            cls.engine.dispose()
    
    def setup_method(self):
        """每个测试方法前的设置"""
        # 创建新的数据库会话
        self.db = self.TestingSessionLocal()
        
        # 创建测试数据
        self._create_test_data()
    
    def teardown_method(self):
        """每个测试方法后的清理"""
        # 清理数据库
        if self.db:
            # 删除所有数据
            for table in reversed(Base.metadata.sorted_tables):
                self.db.execute(table.delete())
            self.db.commit()
            self.db.close()
    
    def _create_test_data(self):
        """创建基础测试数据"""
        # 创建测试角色
        self.test_role = Role(
            name="test_role",
            display_name="Test Role",
            description="Test role for testing",
            level=1,
            is_active=True,
            is_system=False
        )
        self.db.add(self.test_role)
        
        # 创建测试权限
        self.test_permission = Permission(
            name="test:permission",
            display_name="Test Permission",
            description="Test permission for testing",
            category="test",
            action="read",
            resource="test",
            is_active=True,
            is_system=False
        )
        self.db.add(self.test_permission)
        
        # 创建测试用户
        self.test_user = User(
            email="test@example.com",
            username="testuser",
            hashed_password="hashed_password",
            full_name="Test User",
            phone="1234567890",
            avatar="avatar.jpg",
            is_active=True,
            is_verified=True,
            is_superuser=False
        )
        self.db.add(self.test_user)
        
        # 提交基础数据
        self.db.commit()
        
        # 刷新对象以获取ID
        self.db.refresh(self.test_role)
        self.db.refresh(self.test_permission)
        self.db.refresh(self.test_user)
        
        # 创建关联关系
        user_role = UserRole(
            user_id=self.test_user.id,
            role_id=self.test_role.id,
            is_active=True
        )
        self.db.add(user_role)
        
        role_permission = RolePermission(
            role_id=self.test_role.id,
            permission_id=self.test_permission.id,
            is_active=True
        )
        self.db.add(role_permission)
        
        # 提交关联关系
        self.db.commit()
    
    def create_test_user(self, user_id: int = None, **kwargs) -> User:
        """创建测试用户"""
        user_data = {
            "email": kwargs.get('email', f"test{user_id or 1}@example.com"),
            "username": kwargs.get('username', f"testuser{user_id or 1}"),
            "hashed_password": kwargs.get('hashed_password', "hashed_password"),
            "full_name": kwargs.get('full_name', f"Test User {user_id or 1}"),
            "phone": kwargs.get('phone', "1234567890"),
            "avatar": kwargs.get('avatar', "avatar.jpg"),
            "is_active": kwargs.get('is_active', True),
            "is_verified": kwargs.get('is_verified', True),
            "is_superuser": kwargs.get('is_superuser', False)
        }
        
        user = User(**user_data)
        self.db.add(user)
        self.db.commit()
        self.db.refresh(user)
        return user
    
    def create_test_role(self, role_id: int = None, **kwargs) -> Role:
        """创建测试角色"""
        role_data = {
            "name": kwargs.get('name', f"test_role_{role_id or 1}"),
            "display_name": kwargs.get('display_name', f"Test Role {role_id or 1}"),
            "description": kwargs.get('description', f"Test role {role_id or 1} for testing"),
            "level": kwargs.get('level', 1),
            "is_active": kwargs.get('is_active', True),
            "is_system": kwargs.get('is_system', False)
        }
        
        role = Role(**role_data)
        self.db.add(role)
        self.db.commit()
        self.db.refresh(role)
        return role
    
    def create_test_permission(self, permission_id: int = None, **kwargs) -> Permission:
        """创建测试权限"""
        permission_data = {
            "name": kwargs.get('name', f"test:permission:{permission_id or 1}"),
            "display_name": kwargs.get('display_name', f"Test Permission {permission_id or 1}"),
            "description": kwargs.get('description', f"Test permission {permission_id or 1} for testing"),
            "category": kwargs.get('category', "test"),
            "action": kwargs.get('action', "read"),
            "resource": kwargs.get('resource', "test"),
            "is_active": kwargs.get('is_active', True),
            "is_system": kwargs.get('is_system', False)
        }
        
        permission = Permission(**permission_data)
        self.db.add(permission)
        self.db.commit()
        self.db.refresh(permission)
        return permission
    
    def assign_role_to_user(self, user_id: int, role_id: int) -> UserRole:
        """为用户分配角色"""
        user_role = UserRole(
            user_id=user_id,
            role_id=role_id,
            is_active=True
        )
        self.db.add(user_role)
        self.db.commit()
        self.db.refresh(user_role)
        return user_role
    
    def assign_permission_to_role(self, role_id: int, permission_id: int) -> RolePermission:
        """为角色分配权限"""
        role_permission = RolePermission(
            role_id=role_id,
            permission_id=permission_id,
            is_active=True
        )
        self.db.add(role_permission)
        self.db.commit()
        self.db.refresh(role_permission)
        return role_permission
    
    def get_user_with_roles(self, user_id: int) -> User:
        """获取包含角色的用户"""
        user = self.db.query(User).filter(User.id == user_id).first()
        if user:
            # 加载关联的角色
            user.roles = self.db.query(Role).join(UserRole).filter(
                UserRole.user_id == user_id,
                UserRole.is_active == True
            ).all()
        return user
    
    def get_role_with_permissions(self, role_id: int) -> Role:
        """获取包含权限的角色"""
        role = self.db.query(Role).filter(Role.id == role_id).first()
        if role:
            # 加载关联的权限
            role.permissions = self.db.query(Permission).join(RolePermission).filter(
                RolePermission.role_id == role_id,
                RolePermission.is_active == True
            ).all()
        return role